/*
    SEL - Simple DirectMedia Layer Extension Library
    Copyright (C) 2002 Matej Knopp <knopp@users.sf.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "resources.h"
#include "../base/debug.h"
#include "../base/error.h"
#include "../base/surface.h"
#include "../painter/font.h"

namespace SEL
{

ResourceSurface::ResourceSurface (const std::string &name,
				  const std::string &location,
				  const ResourceProperties &properties)
	: Resource (name, location, properties)
{
	m_surface = NULL;
	m_type = "surface";
	m_format[0] = 0;
	if (m_properties.exists ("format"))
	{
		if (m_properties.get ("format").value ().length () >= 3)
		{
			const std::string &value = 
				m_properties.get ("format").value ();
			memcpy (m_format, value.c_str (), 3);
		}
	}
}

ResourceSurface::~ResourceSurface ()
{
	if (loaded ())
		free ();
}	

void 
ResourceSurface::load (RWops &ops)
{
	if (loaded ())
		free ();
		
	SDL::Surface *surface;
	
	if (m_format[0] == 0)
		surface = IMG::Load_RW (ops.rwops (), false);
	else
		surface = IMG::LoadTyped_RW (ops.rwops (), false,
					     m_format);

	m_surface = new Surface (surface);
	if (m_properties.exists ("colorkey"))
	{
		ResourceProperty & prop = m_properties.get ("colorkey");
		Uint32 colorkey;
		if (prop.count () == 3)
			colorkey = m_surface->mapRGB (prop.asInteger(0),
						      prop.asInteger(1),
						      prop.asInteger(2));
		else if (prop.count () == 4) // ??
			colorkey = m_surface->mapRGBA (prop.asInteger(0),
						       prop.asInteger(1),
						       prop.asInteger(2),
						       prop.asInteger(3));
		else 
			colorkey = prop.asInteger();
			
		Uint32 flags = SDL::SRCCOLORKEY;
		if (m_properties.exists ("rle_accel"))
		{
			if (m_properties.get("rle_accel").asInteger () == 1 ||
			    m_properties.get("rle_accel").value () == "true")
			{
				debugI ("RES: RLE accelerated surface.");
				flags |= SDL::RLEACCEL;
			}
		}
		m_surface->setColorKey (colorkey, flags);
	}
}


void 
ResourceSurface::free ()
{
	if (m_surface)
		m_surface->unref ();
	m_surface = NULL;
}

Surface *
ResourceSurface::clone ()
{
	bool was_loaded = loaded ();
	if (!loaded ()) 
		Resource::load ();
		
	Surface *surface = m_surface;
	m_surface = NULL;
		
	if (was_loaded)
		Resource::load ();
			
	return surface;
}

Surface *
getSurface (Resource *res)
{
	if (!res || res->type () != "surface")
		throw Error ("Invalid resource type!\n");
	return (Surface*) res->data ();		
}

ResourceFont::ResourceFont (const std::string &name,
			    const std::string &location,
			    const ResourceProperties &properties)
	: ResourceSurface (name, location, properties)
{
	m_font = NULL;
	m_type = "font";
};

ResourceFont::~ResourceFont ()
{
	if (loaded ())
		free ();
}

void 
ResourceFont::load (RWops &ops)
{
	if (loaded ())
		free ();

	ResourceSurface::load (ops);

	std::string map;
	if (m_properties.exists ("map"))
		map = m_properties.get ("map").value ();

	Uint16 space_width = 8;
	if (m_properties.exists ("space_width"))
	{
		if (m_properties.get ("space_width").isInteger ())
			space_width = m_properties.get ("space_width")
					.asInteger ();
	}

	Uint16 min_gap_width = 2;
	if (m_properties.exists ("min_gap_width"))
	{
		if (m_properties.get ("min_gap_width").isInteger ())
			min_gap_width = m_properties.get ("min_gap_width")
					.asInteger ();
	}
		
	Uint16 alpha_treshold = 1;
	if (m_properties.exists ("alpha_treshold"))
	{
		if (m_properties.get ("alpha_treshold").isInteger ())
			alpha_treshold = m_properties.get ("alpha_treshold")
					.asInteger ();
	}
	if (alpha_treshold > 254)
		alpha_treshold = 254;	
	
	Sint16 h_spacing = 1;
	if (m_properties.exists ("h_spacing"))
	{
		if (m_properties.get ("h_spacing").isInteger ())
			h_spacing = m_properties.get ("h_spacing")
					.asInteger ();
	}

	Sint16 v_spacing = 0;
	if (m_properties.exists ("v_spacing"))
	{
		if (m_properties.get ("v_spacing").isInteger ())
			v_spacing = m_properties.get ("v_spacing")
					.asInteger ();
	}	

	m_font = new Font (m_surface, map, space_width, min_gap_width,
			   alpha_treshold);

	m_font->setHSpacing (h_spacing);			   
	m_font->setVSpacing (v_spacing);
	
	ResourceSurface::free ();
}

Font *
ResourceFont::clone ()
{
	bool was_loaded = loaded ();
	if (!loaded ())
		Resource::load ();
		
	Font *font = m_font;
	m_font = NULL;
	
	if (was_loaded)
		Resource::load ();
		
	return font;
}

void 
ResourceFont::free ()
{
	if (m_font)
		m_font->unref ();
	m_font = NULL;
}

static bool DefaultResourcesRegistered = false;
static ResourceTypeRegister <Resource> * DefaultResourceRegister;
static ResourceTypeRegister <ResourceSurface> * SurfaceResourceRegister;
static ResourceTypeRegister <ResourceFont> * FontResourceRegister;

static void 
unregisterDefaultResources ()
{
	if (DefaultResourcesRegistered)
	{
		delete DefaultResourceRegister;
		delete SurfaceResourceRegister;
		delete FontResourceRegister;
		DefaultResourcesRegistered = false;
	}
}

static void 
registerDefaultResources ()
{
	if (!DefaultResourcesRegistered)
	{
		DefaultResourceRegister 
			= new ResourceTypeRegister <Resource> ("default");
	
		SurfaceResourceRegister
			= new ResourceTypeRegister <ResourceSurface> ("surface");

		FontResourceRegister 
			= new ResourceTypeRegister <ResourceFont> ("font");
			
		DefaultResourcesRegistered = true;

		// free the objects at exit		
		atexit (unregisterDefaultResources);
	}
}

Font * 
getFont (Resource *res)
{
	if (!res || res->type () != "font")
		throw Error ("Invalid resource type!\n");
	return (Font*) res->data ();		
}

void
resourcesInit ()
{
	registerDefaultResources ();
}

} // namespace SEL
